/*************************************************************************
 *
 *
 *************************************************************************/
#include "hgeGuiWindowRendererManager.h"
#include "hgeExceptions.h"
#include "renderers/StaticRenderer.h"
#include "renderers/StaticImageRenderer.h"
#include <algorithm>


/*************************************************************************
Static data
*************************************************************************/
template<> WindowRendererManager* Singleton<WindowRendererManager>::ms_Singleton = 0;
WindowRendererManager::OwnedFactoryList WindowRendererManager::d_ownedFactories;

/*************************************************************************
Singleton functions
*************************************************************************/
WindowRendererManager& WindowRendererManager::getSingleton(void)
{
	return Singleton<WindowRendererManager>::getSingleton();
}
WindowRendererManager* WindowRendererManager::getSingletonPtr(void)
{
	return Singleton<WindowRendererManager>::getSingletonPtr();
}

/*************************************************************************
Constructor / Destructor
*************************************************************************/
WindowRendererManager::WindowRendererManager()
{
	char addr_buff[32];
	sprintf(addr_buff, "(%p)", static_cast<void*>(this));
	hgeLogger::getSingleton().logEvent(
		"CEGUI::WindowRendererManager singleton created " + String(addr_buff));

	// complete addition of any pre-added WindowRendererFactory objects
	OwnedFactoryList::iterator i = d_ownedFactories.begin();

	if (d_ownedFactories.end() != i)
	{
		hgeLogger::getSingleton().logEvent(
			"---- Adding pre-registered WindowRendererFactory objects ----");

		for (; d_ownedFactories.end() != i; ++i)
			addFactory(*i);
	}

	registerFactory();
}

WindowRendererManager::~WindowRendererManager()
{
	char addr_buff[32];
	sprintf(addr_buff, "(%p)", static_cast<void*>(this));
	hgeLogger::getSingleton().logEvent(
		"CEGUI::WindowRendererManager singleton destroyed " + String(addr_buff));
}

/*************************************************************************
Is there a WindowRenderer by this name?
*************************************************************************/
bool WindowRendererManager::isFactoryPresent(const String& name) const
{
	return (d_wrReg.find(name) != d_wrReg.end());
}

/*************************************************************************
Get the named WindowRenderer
*************************************************************************/
WindowRendererFactory* WindowRendererManager::getFactory(const String& name) const
{
	WR_Registry::const_iterator i = d_wrReg.find(name);
	if (i != d_wrReg.end())
	{
		return (*i).second;
	}
	throw UnknownObjectException("There is no WindowRendererFactory named '"+name+"' available");
}

/*************************************************************************
Add a new WindowRenderer factory
*************************************************************************/
void WindowRendererManager::addFactory(WindowRendererFactory* wr)
{
	if (wr == 0)
	{
		return;
	}
	if (d_wrReg.insert(std::make_pair(wr->getName(), wr)).second == false)
	{
		throw AlreadyExistsException("A WindowRendererFactory named '"+wr->getName()+"' already exist");
	}

	char addr_buff[32];
	sprintf(addr_buff, "(%p)", static_cast<void*>(wr));
	hgeLogger::getSingleton().logEvent("WindowRendererFactory '"+wr->getName()+
		"' added. " + addr_buff);
}

/*************************************************************************
Remove a factory by name
*************************************************************************/
void WindowRendererManager::removeFactory(const String& name)
{
	WR_Registry::iterator i = d_wrReg.find(name);

	// non-existing or already removed? The latter can happen when more then one Scheme
	// was loaded using the same renderer.
	if (i == d_wrReg.end())
	{
		return;
	}

	// see if we own this factory
	OwnedFactoryList::iterator j = std::find(d_ownedFactories.begin(),
		d_ownedFactories.end(),
		(*i).second);

	char addr_buff[32];
	sprintf(addr_buff, "(%p)", static_cast<void*>((*i).second));

	d_wrReg.erase(name);

	hgeLogger::getSingleton().logEvent("WindowRendererFactory for '" + name +
		"' WindowRenderers removed. " + addr_buff);

	// delete factory object if we created it
	if (j != d_ownedFactories.end())
	{
		hgeLogger::getSingleton().logEvent("Deleted WindowRendererFactory for '" +
			(*j)->getName() +
			"' WindowRenderers.");

		delete (*j);
		d_ownedFactories.erase(j);
	}
}

/*************************************************************************
Create a WindowRenderer instance by factory name
*************************************************************************/
WindowRenderer* WindowRendererManager::createWindowRenderer(const String& name)
{
	WindowRendererFactory* factory = getFactory(name);
	return factory->create();
}

/*************************************************************************
Destroy a WindowRenderer using its factory
*************************************************************************/
void WindowRendererManager::destroyWindowRenderer(WindowRenderer* wr)
{
	WindowRendererFactory* factory = getFactory(wr->getName());
	factory->destroy(wr);
}

void WindowRendererManager::registerFactory()
{
	WindowRendererManager::addFactory(new TplWindowRendererFactory<StaticRenderer>);
	WindowRendererManager::addFactory(new TplWindowRendererFactory<StaticImageRenderer>);
}
